
import re

import data_type

type_map = {
  'bool': bool,
  'dict': dict,
  'float': float,
  'int': int,
  'list': list,
  'set': set,
  'str': basestring,
}

collection_set = {dict, list, set}

def Validate(data):

  if not isinstance(data, data_type.BASE_DATATYPE):
    raise ValueError('Validation can only support validation of '
                     'BASE_DATATYPE children.')

  value_errors = []

  for key, metadata in data.GetSchema().iteritems():
    value = data.get(key, None)
    value_type = type_map[metadata.type]
    collection_type = type_map.get(metadata.get('collection_type', None), None)

    # required: True | False
    if metadata.get('required', False) and value is None:
      value_errors.append('The value for "%s" is required.' % key)

    if not getattr(metadata, 'type', None):
      continue

    if not value is None:
      # type: datetime, date, time, str, int, float, bool, dict
      if not isinstance(value, value_type):
        value_errors.append('The value for "%s" is not of type "%s": %s' %
                            (key, metadata.type, str(value)))
        continue

      # min:
      if hasattr(metadata, 'min'):
        if ((value_type is basestring or value_type in collection_set )
            and len(value) < metadata.min):
          value_errors.append('The value for "%s" fails minimum length of %s' %
                              (key, metadata.min))

      # max:
      if hasattr(metadata, 'max'):
        if ((value_type is basestring or value_type in collection_set)
            and len(value) > metadata.max):
          value_errors.append('The value for "%s" fails maximum length of %s' %
                              (key, metadata.max))

      # regex_validation: < str >
      if hasattr(metadata, 'regex'):
        if value_type is basestring and value is not '':
          if not re.match(metadata.regex, value):
            value_errors.append('Value %s for %s does not meet regex '
                                'validation: %s' %
                                (key, value, metadata.regex))
        if value_type in {list, set}:
          for collection_value in value:
            if not re.match(metadata.regex, collection_value):
              value_errors.append('Value %s in %s does not meet regex '
                                  'validation: %s' %
                                  (collection_value, key, metadata.regex))

      # collection: True | False

      # collection_type: list, set
      # collection_min:
      # collection_max:

  if value_errors:
    raise ValueError(str.join(' ', value_errors))
